#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>


#define SIZE 1024
#define MAX_N 64
#define SEP " "

char* argv[MAX_N];
char PWD[SIZE];
char ENV[SIZE];
// 所有程序退出时的status
int returnVal = 0;

//重定向相关
#define NoneReDir -1
#define StdinRedir 0
#define StdoutRedir 1
#define AppendRedir 2
//当前重定向类型
int RedirType = NoneReDir;
char FileName[SIZE];
const char* filename = FileName;
const char* GetUserName()
{
    const char* username = getenv("USER");   
    if(username == NULL) return "None";
    else return username;
}

const char* GetHostName()
{
    const char* hostname= getenv("HOSTNAME");   
    if(hostname == NULL) return "None";
    else return hostname;
}

const char* GetPWD()
{
    const char* pwd = getenv("PWD");   
    if(pwd  == NULL) return "None";
    else return pwd;
}

int Interactive(char commandline[])
{
    //打印提示行
    char ch = strcmp(GetUserName(), "root") == 0 ? '#' : '$';
    printf("[%s@%s %s]%c ", GetUserName(), GetHostName(), GetPWD(), ch);
    //接收用户输入
    fgets(commandline, SIZE, stdin);
    int len = strlen(commandline);
    //去除字符串末尾的\n， 返回字符串的长度
    commandline[len - 1] = '\0';
    // printf("%s", commandline);
    return len - 1;
}

void GetFileName(char commandline[], int pos)
{
    int len = strlen(commandline);
    int i;
    int idx = 0;
    for (i = pos; i < len; i++)
    {
        if(isalpha(commandline[i]) || isdigit(commandline[i] || commandline[i] == '_'))
            FileName[idx++] = commandline[i]; 
        else break;
    }
    FileName[idx] = '\0';
}

void CheckRedir(char commandline[])
{
    int len = strlen(commandline);
    int i;
    for (i = 0; i < len; )
    {
        if(commandline[i] == '<')
        {
            RedirType = StdinRedir;
            commandline[i++] = '\0';
            //跳过空格，将文件名拷贝到filename中
            GetFileName(commandline, i);
        }
        else if(commandline[i] == '>')
        {
            if(i + 1 < len && commandline[i + 1] == '>')
            {
                RedirType = AppendRedir;
                commandline[i++] = '\0';
                i++;
                //跳过空格，将文件名拷贝到filename中
                GetFileName(commandline, i);
            }
            else 
            {
                RedirType = StdoutRedir;
                commandline[i++] = '\0';
                //跳过空格，将文件名拷贝到filename中
                GetFileName(commandline, i);
              //  int i;
              //  for (i = 0; argv[i]; i++)
              //      printf("%d:%s\n", i, argv[i]);
              //  printf("%d %s\n", RedirType, FileName);
              //  printf("%s\n", commandline);
            }
        }
        else 
            i++;
    }
}


void Split(char commandline[])
{
    CheckRedir(commandline);
    int i = 0;
    argv[i++] = strtok(commandline, SEP);
    while(argv[i++] = strtok(NULL, SEP))
        ;
    if(strcmp("ls", argv[0]) == 0)
    {
        argv[i - 1] = "--color=auto";
        argv[i] = NULL;
    }
}

void Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        //child
       // printf("I am child, pid:%d\n", getpid());
       // printf("%d\n", RedirType);
         //  printf("RedirType : != NoneRedir"); 
         //   if(RedirType == StdinRedir)
         //   {
         //       int fd = open(filename, O_RDONLY);
         //       dup2(fd, 0);
         //   }
         //   else if(RedirType == StdoutRedir)
         //   {
         //      int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
         //      dup2(fd, 1);
         //   }
         //   else if(RedirType == AppendRedir)
         //   {
         //       int fd = open(filename, O_WRONLY | O_CREAT | O_APPEND, 0666);
         //       dup2(fd, 1);
         //   }
         //   else 
         //   {
         //       printf("Nothing has doing.\n");
         //   }
        
               pid_t id = fork();
    if(id == 0)
    {
        int fd = -1;
        if(RedirType == StdinRedir)
        {
            fd = open(filename, O_RDONLY);
            dup2(fd, 0);
        }
        else if(RedirType == StdoutRedir)
        {
            fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC);
            dup2(fd, 1);
        }
        else if(RedirType == AppendRedir)
        {
            fd = open(filename, O_CREAT | O_WRONLY | O_APPEND);
            dup2(fd, 1);
        }
        else
        {
            // do nothing
        }

        // 让子进程执行命名
        execvp(argv[0], argv);
        exit(1);
    }
    int status;
    pid_t rid = waitpid(id, &status, 0);
    if(WIFEXITED(status)) returnVal = WEXITSTATUS(status);
}
}
int Buildincmd()
{
    int ret = 1;
    if(strcmp("cd", argv[0]) == 0)
    {
        ret = 0;
        const char* path = argv[1];
        if(!path) path = getenv("HOME");
        chdir(path);
       
        char pwd[SIZE];
        getcwd(pwd, SIZE);
        
        snprintf(PWD, SIZE, "PWD=%s", pwd);
        putenv(PWD); 
    }
    else if(strcmp(argv[0],"export" ) == 0)
    {
        ret = 0;
        strcpy(ENV, argv[1]);
        putenv(ENV);
    }
    else if(strcmp(argv[0], "echo") == 0)
    {
        ret = 0;
        if(argv[1] == NULL)
        {
            printf("\n");
        }
        else if(strcmp(argv[1], "$?") == 0)
        {
            printf("%d\n", returnVal);
        }
        else if(argv[1][0] == '$')
        {
            char* tmp = getenv(argv[1] + 1);
            if(tmp)
                printf("%s\n", tmp);
        }
        else 
        {
            int i;
            for (i = 1; argv[i]; i++)
                printf("%s ", argv[i]);
            printf("\n");
        }
    }
    return ret;
}

int main()
{
    char commandline[SIZE];
    while(1)
    {
        //输出命令行提示符，并接收用户输入
        int n = Interactive(commandline);
        // 没有输入的情况下(只有一个\n) 
        if(n == 0) continue;
       // printf("commandline: %s\n", commandline);  
        //printf("%s \n %d", commandline, n); 
        
        //分割字符串
        Split(commandline);
        //printf("Split commandline done.\n");
        //bint i;
        // for ( i = 0; argv[i]; i++)
        //  printf("%s\n", argv[i]);
       
        //处理内建命令
        n = Buildincmd();
        if(n == 0) continue;
       // printf("%d Buildincmd done.", n);
        //执行
        Execute();
    }
    return 0;
}
